home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Graphics Unleashed
/
PC Graphics Unleashed.iso
/
ch05
/
adapt.old
< prev
next >
Wrap
Text File
|
1994-06-02
|
37KB
|
891 lines
/*...................... ADAPT.C .................. 6-3-94 ....*/
/* This program demonstrates Adaptive Color Palette generation.*/
/* It reads True Color (24 bit per pixel) TARGA images and */
/* converts them to 8 bit palette images. It also writes out */
/* the converted image as an 8 bit per pixel Palette Color TIFF*/
/* image. */
/*.............................................................*/
#include<malloc.h>
#include<stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include<conio.h>
#include <math.h>
#include<tiff.h>
#include<vsa.h>
/*.............................................................*/
/* Define type struct CUBE first, needed later! */
/*.............................................................*/
struct CUBE {
unsigned x0;
unsigned y0;
unsigned z0;
unsigned x1; // Outside of cube volume!
unsigned y1; // Outside of cube volume!
unsigned z1; // Outside of cube volume!
unsigned vol; // this is the volume of the cube;
long r_avg; // this is the Average Red value for cube
long g_avg; // this is the Average Green value for cube
long b_avg; // this is the Average Blue value for cube
long fsum; // this is the sum of frequencies in cube
long cerr; // this is the NET color error for the cube
float fom; // Figure Of Merit, Worthyness of cube split
};
/*.............................................................*/
/* All of the function prototypes. */
/*.............................................................*/
int adaptive_lut(char *,unsigned char far *,
unsigned char far *);
int volume_hist(char *, unsigned char far *);
void analyze_row(unsigned char far *, int, unsigned char far *);
void bisect_cube(struct CUBE far *,struct CUBE far *);
void gen_cube_color_stats(struct CUBE far *,
unsigned char far *,int);
void validate_cube(struct CUBE far *);
void copy_cube(struct CUBE, struct CUBE far *);
int add_cube_to_list(struct CUBE, int);
int delete_cube_from_list(int, int);
int move_cubes_to_lut(int, unsigned char far *,
unsigned char far *);
void assign_lut_to_colors(unsigned char far *, unsigned);
void replace_pixel(unsigned char *, unsigned, unsigned char *);
void set_adaptive_config(int, int, int);
void get_adaptive_config(int far *, int far *, int far *);
unsigned long read_tga_header(int, int *, int *, int *, int *);
void true_color_lut(void);
/*.............................................................*/
/* Global variables which control the show. */
/*.............................................................*/
int ADPTV_MODE = 0; /*.. Default = 0 (Off) ..*/
int ADPTV_NUM_COLORS = 256; /*.. Default = 256 ..*/
int ADPTV_QUALITY = 50; /*.. Default = 50 ..*/
struct CUBE CUBE_LIST[256];
#define ADPTV_ASSIGN_MODE 0 /*.. This is experimental..*/
void main()
{
char filename[80];
int i,j,size,width,height,type,file_handle,orient, colors;
unsigned char lut[768], rgb[3072], far *vhist;
/*.............................................................*/
/* Set up the Adaptive Palette controls and get the TARGA */
/* image file name. */
/*.............................................................*/
set_adaptive_config(1,256,50);
LOOP:
printf("Input TARGA Image Filename: ");
scanf("%s",filename);
/*.............................................................*/
/* Allocate memory for the Volume Histogram. Then run the */
/* Adaptive Palette code to generate the adaptive palette. */
/*.............................................................*/
if(ADPTV_MODE)
{
printf("\n");
printf("Please Wait, Computing Adaptive Color Palette.\n");
printf("\n");
if((vhist = (unsigned char far *)halloc(32768,1)) == NULL)
{
printf("Can't Allocate Memory for Histogram!\n");
return;
}
colors = adaptive_lut(filename,vhist,lut);
}
/*.............................................................*/
/* Set highest video resolution available. */
/*.............................................................*/
if(vsa_init(0x2105) != 0) /* 1024 x 768 x 256 */
if(vsa_init(0x2103) != 0) /* 800 x 600 x 256 */
if(vsa_init(0x2101) != 0) /* 640 x 480 x 256 */
if(vsa_init(0x2100) != 0) /* 640 x 400 x 256 */
{
printf("Can't set VESA video mode\n");
printf("Is VESA BIOS Extension TSR loaded?\n");
return;
}
/*.............................................................*/
/* Set up Color Palette either to Adaptive Palette or 8 bit RGB*/
/*.............................................................*/
if(ADPTV_MODE)
vsa_write_color_block(0,colors,lut);
else
true_color_lut();
/*.............................................................*/
/* Open the TARGA file and get header info. */
/*.............................................................*/
if((file_handle = open(filename,O_BINARY | O_RDONLY)) == -1)
return;
read_tga_header(file_handle,&width,&height,&type,&orient);
/*.............................................................*/
/* Depending on orientation, read file out-top down or */
/* bottom-up, replace 24 bit pixels with 8 bit palette indexes,*/
/* and display on screen. */
/*.............................................................*/
if(orient == 32)
for(j=0;j<height;j++)
{
read(file_handle,rgb,3*width);
replace_pixel(rgb,width,vhist);
vsa_raster_line(0,width-1,j,rgb);
}
else
for(j=height-1;j>=0;j--)
{
read(file_handle,rgb,3*width);
replace_pixel(rgb,width,vhist);
vsa_raster_line(0,width-1,j,rgb);
}
/*.............................................................*/
/* Close the image file and look for an ESC key to quit. */
/* Otherwise, save new image as an 8 bit TIFF called */
/* NEW.TIF and LOOP for experimentation with a different */
/* input image files. */
/*.............................................................*/
if(ADPTV_MODE)
hfree((unsigned char huge *)vhist);
close(file_handle);
if(getch() == 27)
goto SKIP;
tf_save_file(0,0,width-1,height-1,"new.tif");
vsa_set_svga_mode(0x3);
goto LOOP;
SKIP:
vsa_set_svga_mode(0x3);
return;
} /*..... End MAIN .....*/
/*....................... READ_TGA_HEADER ....... 5-17-94 ....*/
/* This routine parses through a TGA header and returns the */
/* file offset in bytes to the first byte of pixel data. */
/* It also returns image width, height, and type (type 2 is the*/
/* uncompressed 24 bit image type). */
/*.............................................................*/
unsigned long read_tga_header(int handle, int *width,
int *height, int *type,
int *orientation)
{
unsigned long offset;
unsigned char buff[18];
read(handle,buff,18);
offset = 18+buff[0];
*type = buff[2];
*width = *((unsigned *)buff + 6);
*height = *((unsigned *)buff + 7);
*orientation = buff[17];
return offset;
} /*.... END read_tga_header .....*/
/*..................... ADAPTIVE_LUT ............ 5-31-94 .....*/
/* This routine analyzes the True Color image that is */
/* defined in the TARGA file called 'filename' and computes */
/* an Adpative Color Palette which is an optimal selection of */
/* the 256 colors for this particular image. Before calling */
/* this routine, 'array' must have been allocated 32768 bytes!*/
/* First a 32x32x32 volume histogram is computed. Then the */
/* volume histogram "cube" is subdivide into up to 255 cubes */
/* (color clusters) used in the image. One more cube in this */
/* collection is always reserved for BLACK, in RGB space, */
/* (this is done so that images which have few colors will */
/* still get a good solid BLACK color in the CLUT). Finally */
/* it assigns each one of the cubes to each one of the up to */
/* 256 palette entries, and returns the new Color Look Up */
/* Table in the 'color_array'. The function return value is */
/* the number of colors in the 'color_array' and is always */
/* equal to 256 for now (unused colors set to black). */
/* Upon completion, the 32k elements of 'array' store the */
/* palette index for their respective true color value (down */
/* converted to 15 bits). */
/*.............................................................*/
int adaptive_lut(char *filename,unsigned char *array,
unsigned char *color_array)
{
int num_cubes,num_vol,colors,most_cubes;
struct CUBE cube,new_cube;
most_cubes = ADPTV_NUM_COLORS-1;
num_cubes = 0;
VOLUME_HIST(filename,array);
/*.............................................................*/
/* Set up the number of cubes to be generated based on uniform */
/* color VOLUME partitioning. Then, the rest of the cubes are */
/* generated on COLOR ERROR minimizing criteria. */
/*.............................................................*/
num_vol = (ADPTV_QUALITY * most_cubes) / 100;
/*.............................................................*/
/* Initialize first cube. Get its color stats and put it in */
/* cube list. */
/*.............................................................*/
if(most_cubes > 0)
{
cube.x0 = 0;
cube.y0 = 0;
cube.z0 = 0;
cube.x1 = 32;
cube.y1 = 32;
cube.z1 = 32;
gen_cube_color_stats(&cube,array,1);
num_cubes = add_cube_to_list(cube,num_cubes);
}
/*.............................................................*/
/* Subdivide color volume based on minimizing cube Volumes. */
/* Do for 'num_vol' cubes. */
/*.............................................................*/
while(num_cubes < num_vol)
{
if(CUBE_LIST[0].vol <= 1)
break;
copy_cube(CUBE_LIST[0],&cube);
bisect_cube(&cube,&new_cube);
gen_cube_color_stats(&cube,array,1);
gen_cube_color_stats(&new_cube,array,1);
num_cubes = delete_cube_from_list(0,num_cubes);
if(cube.fsum != 0)
num_cubes = add_cube_to_list(cube,num_cubes);
if(new_cube.fsum != 0)
num_cubes = add_cube_to_list(new_cube,num_cubes);
}
/*.............................................................*/
/* Continue subdividing color volume based on minimizing cube */
/* color errors. Do for remaining cubes (up to */
/* 'ADPTV_NUM_COLORS' - 1). */
/*.............................................................*/
while(num_cubes < most_cubes)
{
if(CUBE_LIST[0].vol <= 1)
break;
copy_cube(CUBE_LIST[0],&cube);
bisect_cube(&cube,&new_cube);
gen_cube_color_stats(&cube,array,2);
gen_cube_color_stats(&new_cube,array,2);
num_cubes = delete_cube_from_list(0,num_cubes);
if(cube.fsum != 0)
num_cubes = add_cube_to_list(cube,num_cubes);
if(new_cube.fsum != 0)
num_cubes = add_cube_to_list(new_cube,num_cubes);
}
/*.............................................................*/
/* Add last cube which is BLACK. Force this cube to top of */
/* list (via cube.fom = 1000000000) so that it will end up at */
/* CLUT location 0. */
/*.............................................................*/
cube.x0 = 0;
cube.y0 = 0;
cube.z0 = 0;
cube.x1 = 1;
cube.y1 = 1;
cube.z1 = 1;
gen_cube_color_stats(&cube,array,1);
cube.fom = 1000000000.0;
num_cubes = add_cube_to_list(cube,num_cubes);
/*.............................................................*/
/* Finally, figure out the values for the Color Look Up table. */
/*.............................................................*/
colors = move_cubes_to_lut(num_cubes,array,color_array);
return colors;
} /*..... End adaptive_lut .....*/
/*.......................... VOLUME_HIST ......... 5-31-94 ....*/
/* This routine analyzes a True Color TARGA image file called */
/* 'filename' and generates a 3D R-G-B Volume Histogram which */
/* has 32 elements on a side (32 x 32 x 32). The histogram is */
/* returned in 'vhist[]'. Each element of 'vhist[]' stores a */
/* count from 0 to 255 which is the frequency of occurance for */
/* that color in the image. The count "saturates" at 255. */
/* ("That color" means the value indexing 'vhist') The value */
/* indexing 'vhist' is a 15 bit color value whos 5 MSBs are */
/* Red, then 5 bits Green and finally 5 LSBs of Blue. If the */
/* image file is not found, this routine returns with a error */
/* value of 1, else 0. */
/*.............................................................*/
int VOLUME_HIST(char *filename, unsigned char far *vhist)
{
unsigned i;
int j,width,height,type,file_handle,orient;
unsigned char rgb[3072];
/*.............................................................*/
/* Initialize 32x32x32 R-G-B historgram to all zeros. */
/*.............................................................*/
for(i=0;i<32768;i++)
vhist[i] = 0;
/*.............................................................*/
/* Open the TARGA file and get header info. */
/*.............................................................*/
if((file_handle = open(filename,O_BINARY | O_RDONLY)) == -1)
return 1;
read_tga_header(file_handle,&width,&height,&type,&orient);
/*.............................................................*/
/* Read out pixels from TARGA file and process in */
/* top down or bottom up order depending on orientation. */
/*.............................................................*/
if(orient == 32)
for(j=0;j<height;j++)
{
read(file_handle,rgb,3*width);
analyze_row(rgb,width,vhist);
}
else
for(j=height-1;j>=0;j--)
{
read(file_handle,rgb,3*width);
analyze_row(rgb,width,vhist);
}
/*.............................................................*/
/* Close the image file. */
/*.............................................................*/
close(file_handle);
return 0;
} /*..... End VOLUME_HIST .....*/
/*.................... ANALYZE_ROW ............... 5-31-94 ....*/
/* This routine takes the pixel data for one row of a 24 */
/* bit/pixel image and accumulates data in the 32x32x32 R-G-B */
/* histogram 'vhist'. The pixel data is sent in the 'byte_buf'*/
/* array. The number of pixels in the array is defined by */
/* 'width'. */
/*.............................................................*/
void analyze_row(byte_buf,width,vhist)
unsigned char far *byte_buf,far *vhist;
int width;
{
unsigned sum,i;
for(i=0;i<width;i++)
{
sum = 0;
sum += (byte_buf[3*i+2])/8 << 10; /* RED */
sum += (byte_buf[3*i+1])/8 << 5; /* GREEN */
sum += (byte_buf[3*i] )/8; /* BLUE */
if(vhist[sum] != 255)
vhist[sum]++;
}
return;
} /*..... End analyze_row ......*/
/*........................ BISECT_CUBE ............ 6-1-94 ....*/
/* Input cube in 'cube', output two cubes in 'cube' and */
/* 'new_cube'. Cubes are split along longest axis. New cube */
/* guaranteed to be "validated". */
/*.............................................................*/
void bisect_cube(struct CUBE *pcube,struct CUBE *pnew_cube)
{
unsigned dx,dy,dz;
validate_cube(pcube);
/*.............................................................*/
/* Get red, green, and blue extent of cube. */
/*.............................................................*/
dx = pcube->x1-pcube->x0; /* RED dimension */
dy = pcube->y1-pcube->y0; /* GREEN dimension */
dz = pcube->z1-pcube->z0; /* BLUE dimension */
/*.............................................................*/
/* If red is longest dimension, split red axis of cube. */
/*.............................................................*/
if((dx >= dy) && (dx >= dz))
{
pnew_cube->x0 = (pcube->x1 + pcube->x0)/2;
pnew_cube->y0 = pcube->y0;
pnew_cube->z0 = pcube->z0;
pnew_cube->x1 = pcube->x1;
pnew_cube->y1 = pcube->y1;
pnew_cube->z1 = pcube->z1;
pcube->x1 = pnew_cube->x0;
return;
}
/*.............................................................*/
/* If green is longest dimension, split green axis of cube. */
/*.............................................................*/
if((dy >= dx) && (dy >= dz))
{
pnew_cube->x0 = pcube->x0;
pnew_cube->y0 = (pcube->y1 + pcube->y0)/2;
pnew_cube->z0 = pcube->z0;
pnew_cube->x1 = pcube->x1;
pnew_cube->y1 = pcube->y1;
pnew_cube->z1 = pcube->z1;
pcube->y1 = pnew_cube->y0;
return;
}
/*.............................................................*/
/* If blue is longest dimension, split blue axis of cube. */
/*.............................................................*/
if((dz >= dx) && (dz >= dy))
{
pnew_cube->x0 = pcube->x0;
pnew_cube->y0 = pcube->y0;
pnew_cube->z0 = (pcube->z1 + pcube->z0)/2;
pnew_cube->x1 = pcube->x1;
pnew_cube->y1 = pcube->y1;
pnew_cube->z1 = pcube->z1;
pcube->z1 = pnew_cube->z0;
return;
}
} /*.... END: bisect_cube .....*/
/*................. GEN_CUBE_COLOR_STATS ........... 6-1-94 ...*/
/* Compute cube's color statistics (Volume, Frequency Sum, */
/* Average Color value for Red, Green, and Blue, Color Error, */
/* and Figure-Of-Merit). The color error is the sum of */
/* ABS(color - avg_color)*frequency (sort of) for each color */
/* in cube. */
/*.............................................................*/
void gen_cube_color_stats(struct CUBE *pcube,
unsigned char *array,int mode)
{
unsigned i,j,k,freq;
int dr,dg,db;
unsigned long sum,index,index0,color_error;
long red_avg,grn_avg,blu_avg;
sum = 0;
red_avg = 0;
grn_avg = 0;
blu_avg = 0;
color_error = 0;
/*.............................................................*/
/* Compute cube's volume */
/*.............................................................*/
pcube->vol = (pcube->x1-pcube->x0)*
(pcube->y1-pcube->y0)*
(pcube->z1-pcube->z0);
/*.............................................................*/
/* Compute average red, green and blue values. */
/*.............................................................*/
for(k=pcube->x0;k<pcube->x1;k++)
{
index0 = k<<10;
for(j=pcube->y0;j<pcube->y1;j++)
{
index = index0 + (j<<5) + pcube->z0;
for(i=pcube->z0;i<pcube->z1;i++)
{
freq = array[index];
red_avg += k*freq;
grn_avg += j*freq;
blu_avg += i*freq;
sum += freq;
index ++;
}
}
}
if(sum != 0)
{
red_avg /= sum;
grn_avg /= sum;
blu_avg /= sum;
}
else
{
red_avg = 0;
grn_avg = 0;
blu_avg = 0;
}
/*.............................................................*/
/* Now compute color error. */
/*.............................................................*/
for(k=pcube->x0;k<pcube->x1;k++)
{
index0 = k<<10;
for(j=pcube->y0;j<pcube->y1;j++)
{
index = index0 + (j<<5) + pcube->z0;
for(i=pcube->z0;i<pcube->z1;i++)
{
freq = array[index];
dr = (red_avg-(int)k);
dg = (grn_avg-(int)j);
db = (blu_avg-(int)i);
color_error += freq*sqrt(dr*dr+dg*dg+db*db);
index ++;
}
}
}
pcube->r_avg = red_avg;
pcube->g_avg = grn_avg;
pcube->b_avg = blu_avg;
pcube->fsum = sum;
pcube->cerr = color_error;
/*.............................................................*/
/* You can decide what characteristic is used for the Figure of*/
/* Merit (FOM) by setting 'mode' to 1 - 5. Modes 1 and 2 are */
/* normally used. Modes 3, 4, and 5 are for play. */
/*.............................................................*/
if(mode == 1)
pcube->fom = (float) pcube->vol;
if(mode == 2)
pcube->fom = (float) pcube->cerr;
if(mode == 3)
pcube->fom = (float) pcube->fsum;
if(mode == 4)
pcube->fom = (float)(pcube->cerr)*(float)(pcube->fsum);
if(mode >= 5)
pcube->fom = (float)(pcube->vol-1)*(float)(pcube->fsum);
return;
} /*.... END: gen_cube_color_stats ....*/
/*.................. MOVE_CUBES_TO_LUT ............ 6-3-94 ....*/
/* This routine loads 'color_array' with the colors of the */
/* cubes in the 'CUBE_LIST' (after the 'CUBE_LIST' has been */
/* generated). The return value is the number of colors */
/* loaded into 'color_array', and is always 256. */
/*.............................................................*/
int move_cubes_to_lut(int num_cubes,unsigned char *array,
unsigned char *color_array)
{
unsigned i;
/*.............................................................*/
/* Compute Color Lookup Table entries. You could do this by */
/* taking average of each color component axis of cube. But */
/* instead ... Use the Average color computed earlier for each */
/* cube! (This is more accurate color). Multiply by two to */
/* scale the 5 bit color into the 6 bit palette entry. */
/*.............................................................*/
for(i=0;i < num_cubes;i++)
{
color_array[3*i+0] = 2*CUBE_LIST[i].r_avg;
color_array[3*i+1] = 2*CUBE_LIST[i].g_avg;
color_array[3*i+2] = 2*CUBE_LIST[i].b_avg;
}
/*.............................................................*/
/* Set unused palette entries to black. */
/*.............................................................*/
for(i=num_cubes;i<256;i++)
{
color_array[3*i+0] = 0;
color_array[3*i+1] = 0;
color_array[3*i+2] = 0;
}
assign_lut_to_colors(array,num_cubes);
return 256;
} /*..... End move_cubes_to_lut ......*/
/*................. ASSIGN_LUT_TO_COLORS ........... 6-3-94 ...*/
/* Assign each of the 32768 color values in the RGB Color Space*/
/* (compressed from 16M) to one of the up to 256 cubes (which */
/* map to the color lut). 'ADPTV_ASSIGN_MODE' determines the */
/* way that colors are assigned. If '0', then color error is */
/* minimized. Otherwise, all colors which land within a cube */
/* get set to cube average color. */
/*.............................................................*/
void assign_lut_to_colors(unsigned char *array,unsigned
num_cubes)
{
int red,grn,blu,dr,dg,db,error,last_error;
unsigned i,j,k,n;
long index,index0;
if(!ADPTV_ASSIGN_MODE)
/*.............................................................*/
/* For each color in the image, assign it the CUBE ID for the */
/* CUBE which has the nearest average color value . */
/*.............................................................*/
{
for(i=0;i<32768;i++)
{
if(array[i] != 0)
{
red = (i & 0x7c00) >> 10;
grn = (i & 0x03e0) >> 5;
blu = i & 0x001f ;
last_error = 10000;
for(n=0;n<num_cubes;n++)
{
dr = CUBE_LIST[n].r_avg - red;
dg = CUBE_LIST[n].g_avg - grn;
db = CUBE_LIST[n].b_avg - blu;
error = dr*dr+dg*dg+db*db;
if(error <= last_error)
{
array[i] = n;
last_error = error;
}
}
}
}
}
/*.............................................................*/
/* For each cube, assign its ID to all of the colors in */
/* its boundary. This method is not as accurate as the one */
/* above but its faster. */
/*.............................................................*/
else
{
for(n=0;n<num_cubes;n++)
{
for(k=CUBE_LIST[n].x0;k<CUBE_LIST[n].x1;k++)
{
index0 = k<<10;
for(j=CUBE_LIST[n].y0;j<CUBE_LIST[n].y1;j++)
{
index = index0 + (j<<5) + CUBE_LIST[n].z0;
for(i=CUBE_LIST[n].z0;i<CUBE_LIST[n].z1;i++)
{
array[index] = n;
index ++;
}
}
}
}
}
return;
} /*.... END: assign_lut_to_colors ....*/
/*..................... VALIDATE_CUBE ............ 1-12-94 ....*/
/* Insures that cube point 0 is closer to (or same distance */
/* from) origin of RGB Color than cube point 1. */
/*.............................................................*/
void validate_cube(struct CUBE *pcube)
{
unsigned temp;
if(pcube->x0 > pcube->x1)
{
temp = pcube->x0;
pcube->x0 = pcube->x1;
pcube->x1 = temp;
}
if(pcube->y0 > pcube->y1)
{
temp = pcube->y0;
pcube->y0 = pcube->y1;
pcube->y1 = temp;
}
if(pcube->z0 > pcube->z1)
{
temp = pcube->z0;
pcube->z0 = pcube->z1;
pcube->z1 = temp;
}
return;
} /*.... END: validate_cube ...*/
/*........................... COPY_CUBE .......... 1-15-94 ....*/
/* This routine copies the 'cube' struct to the 'new_cube' */
/* struct. */
/*.............................................................*/
void copy_cube(struct CUBE cube,struct CUBE *pnew_cube)
{
pnew_cube->x0 = cube.x0;
pnew_cube->y0 = cube.y0;
pnew_cube->z0 = cube.z0;
pnew_cube->x1 = cube.x1;
pnew_cube->y1 = cube.y1;
pnew_cube->z1 = cube.z1;
pnew_cube->vol = cube.vol;
pnew_cube->r_avg = cube.r_avg;
pnew_cube->g_avg = cube.g_avg;
pnew_cube->b_avg = cube.b_avg;
pnew_cube->fsum = cube.fsum;
pnew_cube->cerr = cube.cerr;
pnew_cube->fom = cube.fom;
return;
} /*.... END: copy_cube ....*/
/*..................... ADD_CUBE_TO_LIST ........... 6-1-94 ...*/
/* Adds a cube to list. Inserts cube appropriately to maintain*/
/* a descending cube sort based on CUBE_LIST[i].fom. In */
/* otherwords, CUBE_LIST[0].fom is always going to be the */
/* largest value of all cubes. Give this routine a cube and */
/* the current number of cubes in the list 'n'. Routine returns*/
/* the new value of 'n'. NOTE: For n cubes, you have */
/* CUBE_LIST[0] thru CUBE_LIST[n-1]. */
/*.............................................................*/
int add_cube_to_list(struct CUBE new_cube,int n)
{
int m;
m = n+1;
/*.............................................................*/
/* Bump lower FOM valued cubes down a step in cube list. */
/*.............................................................*/
if(n>0)
while(CUBE_LIST[n-1].fom <= new_cube.fom)
{
CUBE_LIST[n].x0 = CUBE_LIST[n-1].x0;
CUBE_LIST[n].y0 = CUBE_LIST[n-1].y0;
CUBE_LIST[n].z0 = CUBE_LIST[n-1].z0;
CUBE_LIST[n].x1 = CUBE_LIST[n-1].x1;
CUBE_LIST[n].y1 = CUBE_LIST[n-1].y1;
CUBE_LIST[n].z1 = CUBE_LIST[n-1].z1;
CUBE_LIST[n].vol = CUBE_LIST[n-1].vol;
CUBE_LIST[n].r_avg = CUBE_LIST[n-1].r_avg;
CUBE_LIST[n].g_avg = CUBE_LIST[n-1].g_avg;
CUBE_LIST[n].b_avg = CUBE_LIST[n-1].b_avg;
CUBE_LIST[n].fsum = CUBE_LIST[n-1].fsum;
CUBE_LIST[n].cerr = CUBE_LIST[n-1].cerr;
CUBE_LIST[n].fom = CUBE_LIST[n-1].fom;
n--;
if(n==0) break;
}
/*.............................................................*/
/* Add new cube to cube list. */
/*.............................................................*/
CUBE_LIST[n].x0 = new_cube.x0;
CUBE_LIST[n].y0 = new_cube.y0;
CUBE_LIST[n].z0 = new_cube.z0;
CUBE_LIST[n].x1 = new_cube.x1;
CUBE_LIST[n].y1 = new_cube.y1;
CUBE_LIST[n].z1 = new_cube.z1;
CUBE_LIST[n].vol = new_cube.vol;
CUBE_LIST[n].r_avg = new_cube.r_avg;
CUBE_LIST[n].g_avg = new_cube.g_avg;
CUBE_LIST[n].b_avg = new_cube.b_avg;
CUBE_LIST[n].fsum = new_cube.fsum;
CUBE_LIST[n].cerr = new_cube.cerr;
CUBE_LIST[n].fom = new_cube.fom;
return m;
} /*.. END: add_cube_to_list ..*/
/*................... DELETE_CUBE_FROM_LIST ...... 1-15-94 ....*/
/* Deletes cube 'p' from cube list. Bumps up remaining cubes to*/
/* keep list consecutive and hole free. Give this routine the */
/* current number of cubes in list ('n') and the cube id to be */
/* deleted ('p'). Routine returns the new value of 'n'. */
/* NOTE: For n cubes, you have CUBE_LIST[0] thru CUBE_LIST[n-1]*/
/*.............................................................*/
int delete_cube_from_list(int p,int n)
{
if(p >= n)
return n;
while(p < n-1)
{
CUBE_LIST[p].x0 = CUBE_LIST[p+1].x0;
CUBE_LIST[p].y0 = CUBE_LIST[p+1].y0;
CUBE_LIST[p].z0 = CUBE_LIST[p+1].z0;
CUBE_LIST[p].x1 = CUBE_LIST[p+1].x1;
CUBE_LIST[p].y1 = CUBE_LIST[p+1].y1;
CUBE_LIST[p].z1 = CUBE_LIST[p+1].z1;
CUBE_LIST[p].vol = CUBE_LIST[p+1].vol;
CUBE_LIST[p].r_avg = CUBE_LIST[p+1].r_avg;
CUBE_LIST[p].g_avg = CUBE_LIST[p+1].g_avg;
CUBE_LIST[p].b_avg = CUBE_LIST[p+1].b_avg;
CUBE_LIST[p].fsum = CUBE_LIST[p+1].fsum;
CUBE_LIST[p].cerr = CUBE_LIST[p+1].cerr;
CUBE_LIST[p].fom = CUBE_LIST[p+1].fom;
p++;
}
return n-1;
} /*.. END: delete_cube_from_list ..*/
/*..................... REPLACE_PIXEL.C ............ 6-1-94 ...*/
/* This routine compresses the 3 byte per pixel data in the */
/* array 'byte_buf' into a single byte per pixel data array */
/* (back into 'byte_buf'). The 8-8-8 RGB pixel is down */
/* converted to a 5-5-5 RGB pixel. Then, the 15 bit RGB */
/* pixel value is used to look up in the 'array' to get the 8 */
/* bit palette index for that color. The number of pixels in */
/* 'byte_buf' is defined by 'width'. */
/*.............................................................*/
void replace_pixel(unsigned char *byte_buf,unsigned
width,unsigned char *array)
{
int i,sum;
/*.............................................................*/
/* If Adaptive Palette ON, map pixel to adaptive palette. */
/*.............................................................*/
if(ADPTV_MODE)
for(i=0;i<width;i++)
{
sum = 0;
sum += (byte_buf[3*i+2])/8 << 10; /* RED */
sum += (byte_buf[3*i+1])/8 << 5; /* GREEN */
sum += (byte_buf[3*i] )/8; /* BLUE */
byte_buf[i] = array[sum];
}
/*.............................................................*/
/* If Adaptive Palette OFF, map pixel to 8 bit RGB palette. */
/*.............................................................*/
else
for(i=0;i<width;i++)
{
sum = 0;
sum += (byte_buf[3*i+2])/32 << 5; /* RED */
sum += (byte_buf[3*i+1])/32 << 2; /* GREEN */
sum += (byte_buf[3*i] )/64; /* BLUE */
byte_buf[i] = (unsigned char) sum;
}
return;
} /*..... End replace_pixel ......*/
/*................ SET_ADAPTIVE_CONFIG ........... 4-30-94 ....*/
/* This routine configures the operation of the TIFF256 library*/
/* with regards to 24 bit/pixel images. The input parameters */
/* have are: */
/* */
/* enable - Adaptive Palette is enabled when enable */
/* is 1. disabled otherwise. */
/* num_colors - This parameter determines how many colors */
/* the 16M color image will be reduced to. */
/* (2 min, 256 max!) */
/* quality - This parameter lets the user optimize the */
/* Adaptive Palette algorithm for image */
/* quality. The valid range is from 0 to 100.*/
/* For values closer to 0, the algorithm is*/
/* optimized for images with fewer colors, */
/* but many shades per color (smooth shading */
/* is emphasized at the expense of color */
/* variety). */
/* For values closer to 100, the algorithm */
/* is optimized for images with a broader */
/* color distribution (many colors are */
/* accomodated at the expense of shade */
/* continuity). */
/*.............................................................*/
void set_adaptive_config(int enable,int num_colors,int quality)
{
ADPTV_MODE = enable;
ADPTV_NUM_COLORS = num_colors;
ADPTV_QUALITY = quality;
if(ADPTV_NUM_COLORS > 256) ADPTV_NUM_COLORS = 256;
if(ADPTV_NUM_COLORS < 2) ADPTV_NUM_COLORS = 2;
if(ADPTV_QUALITY > 100) ADPTV_QUALITY = 100;
return;
}
/*................. GET_ADAPTIVE_CONFIG ............ 4-10-94 ..*/
/* This routine returns the current Adaptive Palette */
/* configuration parameters (which were set by */
/* set_adaptive_config(). */
/*.............................................................*/
void get_adaptive_config(int *penable,int *pnum_colors,
int *pquality)
{
*penable = ADPTV_MODE;
*pnum_colors = ADPTV_NUM_COLORS;
*pquality = ADPTV_QUALITY;
return;
}
/*.................... TRUE_COLOR_LUT.C .......... 5-15-94 ....*/
/* This routine generates a 'true color' LUT. An 8 bit index */
/* into the LUT represents 3 bits of RED, 3 bits of GREEN, and */
/* 2 bits of BLUE. The 3 msbs of the 8 bit index are the RED */
/* field, next 3 are GREEN, and the 2 lsbs are the BLUE field. */
/* */
/*.............................................................*/
void true_color_lut(void)
{
int i;
unsigned char color_array[768];
for(i=0;i<256;i++)
{
color_array[3*i+0]= ((i & 0x00e0) >> 5) * 9;
color_array[3*i+1]= ((i & 0x001c) >> 2) * 9;
color_array[3*i+2]= (i & 0x0003) * 21;
}
vsa_write_color_block(0,256,color_array);
return;
} /*..... End true_color_lut .....*/